<!--
 * @Author: hq
 * @Date: 2022-07-21 19:04:50
 * @LastEditors: hq
 * @LastEditTime: 2022-08-03 14:58:14
 * @Description: your project
 * @version: 1.0
-->
<template>
  <div class="info" v-loading="loadingStatus">
    <el-row v-if="list.length > 0">
      <el-col :span="7">
        <div class="left">
          <div
            class="list"
            :class="[active === index ? 'active' : '']"
            @click="handleList(item, index)"
            v-for="(item, index) in list"
            :key="index"
          >
            <img :src="item.avatar" mode="" />
            <div class="m">
              <div class="row1">
                <div>{{ item.nickname }}</div>
                <div>{{ item.time }}</div>
              </div>
              <div class="row2">
                <div>
                  {{ item.context }}
                </div>
                <div v-if="item.count > 0">{{ item.count }}</div>
              </div>
            </div>
          </div>
        </div>
      </el-col>
      <el-col :span="17">
        <div class="right" v-if="active != null">
          <div class="top">{{ list[active].nickname }}</div>
          <div class="middle_info" id="infoH" ref="infoH">
            <div
              class="chatRecord hand_cs"
              @click="handleChatRecord"
              v-if="loading === 1"
            >
              查看聊天记录
            </div>
            <div class="chatRecord1" v-if="loading === 2">
              <i class="el-icon-loading"></i>加载中
            </div>
            <div class="chatRecord1 hand_cs" v-if="loading === 3">
              -- 没有更多了 --
            </div>
            <div class="chat" v-for="(item, index) in chatArr" :key="index">
              <div class="l" v-if="item.align === 'left'">
                <img class="header" :src="item.avatar" alt="" />
                <div class="send_info" v-if="item.context.class === 'text'">
                  {{ item.context.data }}
                </div>
                <el-image
                  class="send_img"
                  v-if="item.context.class === 'image'"
                  :src="item.context.data"
                  :preview-src-list="srcList"
                ></el-image>
              </div>
              <div class="r" v-if="item.align === 'right'">
                <div class="r_row">
                  <i v-if="item.txt_status == 1" class="el-icon-loading"></i>
                  <img
                    v-if="item.txt_status == 2"
                    class="err"
                    src="@/assets/error.png"
                    mode=""
                  />
                  <div class="send_info" v-if="item.context.class === 'text'">
                    {{ item.context.data }}
                  </div>
                  <el-image
                    class="send_img"
                    v-if="item.context.class === 'image'"
                    :src="item.context.data"
                    :preview-src-list="srcList"
                  ></el-image>
                  <img class="header" :src="item.avatar" alt="" />
                </div>
                <div class="yd">
                  {{ item.status === 1 ? "已读" : "未读" }}
                </div>
              </div>
            </div>
          </div>
          <div class="bottom">
            <el-input
              @click.native="focus"
              v-model="inputContent"
              type="textarea"
              :rows="4"
            ></el-input>
            <!-- <img @click="handleUpload" src="@/assets/img.png" mode="" /> -->
            <div class="send1 hand_cs">
              <el-upload
                class="avatar-uploader"
                action=""
                :show-file-list="false"
                :http-request="handleUpload"
              >
                <img src="@/assets/img.png" mode="" />
              </el-upload>
            </div>
            <div
              class="send hand_cs"
              @click="handleSend"
              @keyup.enter="handleSend"
            >
              发送
            </div>
          </div>
        </div>
        <div v-if="active === null" class="zwsj">点击左侧列表进行聊天</div>
      </el-col>
    </el-row>
    <div v-else class="zwsj">暂无聊天消息</div>
  </div>
</template>

<script>
import {
  chatList,
  sendMsg,
  getAuthorization,
  getRecord,
  alreadyRead,
} from "@/api/chat";
import getCurrentTime from "@/utils/cuurentTime";
import upImg from "@/utils/upimg";
export default {
  data() {
    return {
      loadingStatus: true,
      loading: 2,
      active: null,
      list: [],
      chatArr: [],
      inputContent: "", //发送内容
      page: 1,
      srcList: [],
      rightHeaderUrl: "",
      middle_info_height: "",
      ws: "",
    };
  },
  methods: {
    //左侧消息列表接口
    async chatList() {
      const { list, err } = await chatList({});
      if (err === 0) {
        this.list = list.data;
        this.handleList(this.list[0], 0);
      }
    },
    //查询聊天记录接口
    async getRecord() {
      const { list, err } = await getRecord({
        page: this.page,
        uuid: this.list[this.active].uuid,
      });
      if (err === 0) {
        this.loadingStatus = false;
        if (list.data.length < 15) {
          this.loading = 3;
        } else {
          this.loading = 1;
        }
        this.chatArr = list.data.reverse().concat(this.chatArr);
        this.chatArr.forEach((item) => {
          if (item.context.class === "image") {
            this.srcList.push(item.context.data);
          }
        });
        this.toNotice(list.data);
        if (this.page === 1) {
          //第一页回到底部
          this.$nextTick(() => {
            this.focus();
          });
        }
      }
    },
    //获取聊天记录查看了对方的消息通知对方已读
    toNotice(data) {
      let other = [];
      data.forEach((item) => {
        if (item.align === "left") {
          other.push(item.msgid);
          item.status = 1;
        }
      });
      //如果有未读的  筛选出来通知对方已读
      if (other.length > 0) {
        this.alreadyRead(other.join(","));
      }
    },
    //获取授权链接websocket
    async getAuthorization() {
      const { data, err } = await getAuthorization({});
      if (err === 0) {
        this.connectSocket(data.wss, data.token);
      }
    },
    //已读接口
    async alreadyRead(id) {
      const { err } = await alreadyRead({ msgid: id });
      if (err === 0) {
        //
      }
    },
    //点击左侧消息列表
    handleList(item, index) {
      this.loadingStatus = true;
      this.$set(item, "count", 0);
      if (this.active != index) {
        this.loading = 2;
        this.page = 1;
        this.chatArr = [];
        this.active = index;
        this.getRecord();
      }
    },
    //发送消息接口
    async sendMsg(type, info) {
      const { data, err } = await sendMsg({
        to: this.list[this.active].uuid,
        context: JSON.stringify({ class: type, data: info }),
      });
      if (err === 0) {
        //成功
        this.chatArr[this.chatArr.length - 1].txt_status = null;
        this.chatArr[this.chatArr.length - 1].msgid = data.msgid;
        //强制赋值
        if (type === "text") {
          this.$set(this.list[this.active], "context", info);
        } else {
          this.$set(this.list[this.active], "context", "[图片]");
        }
        this.$set(this.list[this.active], "time", getCurrentTime());
      } else {
        this.chatArr[this.chatArr.length - 1].txt_status = 2;
      }
    },
    //发送消息
    handleSend() {
      if (this.inputContent === "") {
        this.$notify({
          title: "警告",
          message: "不能发送空白消息",
          type: "warning",
        });
      } else {
        //发送文字
        let msg = {
          align: "right",
          txt_status: 1,
          status: 0,
          context: {
            class: "text",
            data: this.inputContent,
          },
          avatar: this.rightHeaderUrl,
        };
        this.chatArr.push(msg);
        this.sendMsg("text", this.inputContent);
        this.inputContent = "";
        this.$nextTick(() => {
          this.focus();
        });
      }
    },
    //发送图片
    handleUpload(file) {
      upImg.upimg(
        (data) => {
          //发送图片
          let msg = {
            align: "right",
            txt_status: 1,
            status: 0,
            context: {
              class: "image",
              data: data.data.url,
            },
            avatar: this.rightHeaderUrl,
          };
          this.chatArr.push(msg);
          this.srcList.push(msg.context.data);
          this.sendMsg("image", data.data.url);
          //回到底部
          this.$nextTick(() => {
            this.focus();
          });
        },
        1,
        file
      );
    },
    // 连接websocket
    connectSocket(url, token) {
      // 打开一个 web socket
      this.ws = new WebSocket(url + "?action=auth?token=" + token);
      this.ws.onopen = () => {
        //连接成功回调
        console.log("Socket已连接--------->>>>");
        this.ws.send(
          JSON.stringify({
            action: "auth",
            token: token,
          })
        ); //连接成功之后发送消息
      };

      this.ws.onmessage = (msg) => {
        //接收到消息回调
        let data = JSON.parse(msg.data);
        if (data.action === "auth") {
          //认证成功 处理头像
          this.rightHeaderUrl = data.data.avatar;
          setTimeout(() => {
            this.ws.send(
              JSON.stringify({
                action: "ping",
              })
            );
          }, 2000);
        } else if (data.action === "ping") {
          setTimeout(() => {
            this.ws.send(
              JSON.stringify({
                action: "ping",
              })
            );
          }, 2000);
        } else if (
          data.action === "message" &&
          data.from.uuid === this.list[this.active].uuid
        ) {
          let msg = {
            align: "left",
            context: data.message,
            msgid: data.msgid,
            avatar: data.from.avatar,
          };
          this.chatArr.push(msg);
          //回到底部
          this.$nextTick(() => {
            this.focus();
          });
          this.alreadyRead(data.msgid); //已读接口
          //强制更新左侧列表
          if (data.message.class === "text") {
            this.$set(this.list[this.active], "context", data.message.data);
          } else {
            this.$set(this.list[this.active], "context", "[图片]");
          }
          this.$set(this.list[this.active], "time", getCurrentTime());
        } else if (
          data.action === "message" &&
          data.from.uuid !== this.list[this.active].uuid
        ) {
          //推送了消息 不是当前聊天对象  需要更新列表消息条数
          this.list.forEach((item) => {
            if (item.uuid == data.from.uuid) {
              //强制更新
              this.$set(item, "count", item.count + 1);
              if (data.message.class === "text") {
                this.$set(item, "context", data.message.data);
              } else {
                this.$set(item, "context", "[图片]");
              }
              this.$set(item, "time", getCurrentTime());
              return false;
            }
          });
          let flag = this.list.some((item) => {
            return item.uuid == data.from.uuid;
          });
          if (!flag) {
            //列表新增数据
            this.list.unshift({
              avatar: data.from.avatar,
              context:
                data.message.class === "text" ? data.message.data : "[图片]",
              count: 1,
              nickname: data.from.nickname,
              time: getCurrentTime(),
              uuid: data.from.uuid,
            });
            this.active += 1;
            console.log(this.list);
          }
        } else if (data.action === "msg.status") {
          //通知已读
          this.chatArr.forEach((item, index) => {
            data.msgid.split(",").forEach((v, i) => {
              if (item.msgid == v) {
                this.$set(this.chatArr[index], "status", 1);
              }
            });
          });
        }
      };

      this.ws.onclose = () => {
        //socket连接关闭时回调
        console.log("Socket关闭---------------->>>>>");
      };

      this.ws.onerror = (err) => {
        console.log(err, "Socket连接错误-------->>>>>>");
      };
    },
    //点击查看聊天记录
    handleChatRecord() {
      this.loading = 2;
      this.page++;
      this.getRecord();
    },
    //点击输入框聚焦
    focus() {
      var infoH = document.getElementById("infoH");
      infoH.scrollTop = infoH.scrollHeight;
    },
    // // 点击回车键登录
    keyDown(e) {
      // 回车则执行登录方法 enter键的ASCII是13
      if (e.keyCode === 13) {
        this.handleSend(); // 发送消息
      }
    },
  },
  mounted() {
    // 绑定监听事件
    window.addEventListener("keydown", this.keyDown);
  },
  destroyed() {
    //离开页面关闭Socket连接
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
    // 销毁事件
    window.removeEventListener("keydown", this.keyDown, false); //销毁回车事件，如果不销毁，在其他页面敲回车也会执行操作。
  },
  created() {
    this.chatList();
    // setTimeout(() => {
    //   this.list.unshift({});
    //   this.active += 1;
    // }, 2000);
    this.getAuthorization();
  },
};
</script>

<style lang="scss" scoped>
.info {
  background-color: #fff;
  box-shadow: 0px 0px 10px rgb(219, 218, 218);
  border-radius: 4px;
  //   padding: 20px;
  box-sizing: border-box;
  box-sizing: border-box;
  height: calc(100vh - 100px);
  *::-webkit-scrollbar {
    width: 10px;
    height: 10px;
  }
  *::-webkit-scrollbar-track {
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
  }
  *::-webkit-scrollbar-thumb {
    background-color: #e7e9e9;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
  }
  .left {
    height: calc(100vh - 100px);
    overflow: auto;
    border-right: 1px solid rgb(234, 234, 234);

    .list {
      display: flex;
      padding: 20px;
      box-sizing: border-box;
      &:hover {
        cursor: pointer;
        background-color: #e7e7e7;
      }

      img {
        width: 50px;
        height: 50px;
        border-radius: 50%;
        flex-shrink: 0;
      }
      .m {
        flex: 1;
        width: 70%;
        padding-left: 20px;
        box-sizing: border-box;
        .row1,
        .row2 {
          display: flex;
          justify-content: space-between;
        }
        .row1 {
          margin-bottom: 10px;
          div:nth-child(1) {
            font-size: 16px;
            font-weight: 600;
          }
          div:nth-child(2) {
            color: #888888;
          }
        }
        .row2 {
          div:nth-child(1) {
            width: 80%;
            font-size: 14px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            word-break: break-all;
          }
          div:nth-child(2) {
            flex-shrink: 0;
            color: #888888;
            background-color: #d63430;
            color: #fff;
            padding: 2px 6px;
            border-radius: 40px;
            font-size: 12px;
          }
        }
      }
    }
    .active {
      background-color: #dcdcdc !important;
    }
  }
  .right {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    .top {
      height: 100px;
      line-height: 100px;
      font-size: 20px;
      padding-left: 40px;
      box-sizing: border-box;
      border-bottom: 1px solid rgb(234, 234, 234);
    }
    .middle_info {
      height: calc(100vh - 350px);
      overflow: auto;
      padding: 0 20px;
      box-sizing: border-box;
      .chatRecord {
        text-align: center;
        color: #999999;
        height: 50px;
        line-height: 50px;
      }
      .chatRecord1 {
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 14px;
        color: #999999;
        height: 50px;
        line-height: 50px;
        i {
          font-size: 22px;
          margin-right: 5px;
        }
      }
      .chat {
        margin-bottom: 20px;
        .l {
          display: flex;
          align-items: center;
          .header {
            width: 45px;
            height: 45px;
            border-radius: 50%;
            flex-shrink: 0;
            margin-right: 20px;
          }
          .send_info {
            background-color: rgb(233, 233, 233);
            border-radius: 4px;
            padding: 10px;
            box-sizing: border-box;
            position: relative;
            max-width: 50%;
            min-width: 40px;
            min-height: 40px;
            word-break: break-all;
            &::before {
              position: absolute;
              top: 36%;
              left: -13px;
              content: "";
              border-top: 10px solid rgb(233, 233, 233);
              border-left: 10px solid transparent;
              border-right: 10px solid transparent;
              transform: rotate(90deg);
            }
            // border
          }
          .send_img {
            width: 100px;
            height: 100px;
            border-radius: 4px;
            &:hover {
              cursor: pointer;
            }
          }
        }
        .r {
          .r_row {
            display: flex;
            align-items: center;
            justify-content: flex-end;
            font-size: 20px;
          }
          .yd {
            width: 100%;
            text-align: end;
            padding-right: 66px;
            box-sizing: border-box;
            font-size: 12px;
            color: #999999;
          }
          i {
            margin-right: 10px;
          }
          .err {
            width: 24px;
            height: 24px;
            margin-right: 10px;
          }
          .header {
            width: 45px;
            height: 45px;
            border-radius: 50%;
            flex-shrink: 0;
            margin-left: 20px;
          }
          .send_info {
            background-color: #d63430;
            border-radius: 4px;
            padding: 10px;
            box-sizing: border-box;
            position: relative;
            color: #fff;
            max-width: 50%;
            min-width: 40px;
            min-height: 40px;
            word-break: break-all;
            font-size: 14px;
            &::before {
              position: absolute;
              top: 36%;
              right: -13px;
              content: "";
              border-bottom: 10px solid #d63430;
              border-left: 10px solid transparent;
              border-right: 10px solid transparent;
              transform: rotate(90deg);
            }
            // border
          }
          .send_img {
            width: 100px;
            height: 100px;
            border-radius: 4px;
            &:hover {
              cursor: pointer;
            }
          }
        }
      }
    }
    .bottom {
      height: 150px;
      border-top: 1px solid rgb(234, 234, 234);
      position: relative;
      /deep/.el-textarea__inner {
        border: 0;
        color: #333333;
        font-size: 16px;
      }
      ::-webkit-scrollbar {
        width: 8px;
        height: 8px;
      }
      ::-webkit-scrollbar-track {
        -webkit-border-radius: 3px;
        -moz-border-radius: 3px;
        border-radius: 3px;
      }
      ::-webkit-scrollbar-thumb {
        background-color: #e7e9e9;
        -webkit-border-radius: 3px;
        -moz-border-radius: 3px;
        border-radius: 3px;
      }
      .send {
        position: absolute;
        background-color: #f5f5f5;
        width: 100px;
        height: 38px;
        color: #d63430;
        display: flex;
        justify-content: center;
        align-items: center;
        right: 30px;
        bottom: 10px;
      }
      .send1 {
        position: absolute;
        right: 145px;
        bottom: 13px;
      }
    }
  }
  .zwsj {
    height: calc(100vh - 100px);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #999999;
  }
}
</style>
